/** 
 * <p>Original Author:  jessefreeman</p>
 * <p>Class File: CamoBitmap.as</p>
 * 
 * <p>Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:</p>
 * 
 * <p>The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.</p>
 * 
 * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.</p>
 * 
 * <p>Licensed under The MIT License</p>
 * <p>Redistributions of files must retain the above copyright notice.</p>
 *
 * 	<p>Based on ScaleBitmap 1.2.2 by ByteArray<br/>
 * 	Project page : http://www.bytearray.org/?p=118</p>
 * 
 * <p>Revisions<br/> 
 * 	2.0  Initial version Jan 7, 2009</p>
 *
 */
 
package camo.core.decal
{
	import flash.display.BitmapData;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;

	public class CamoBitmap extends AbstractCamoBitmap
	{
		
		protected var _originalBitmap : BitmapData;
		protected var _scale9Grid : Rectangle = null;
		
		/**
		 * 
		 * @param bmpData
		 * @param pixelSnapping
		 * @param smoothing
		 * 
		 */		
		public function CamoBitmap(bmpData:BitmapData=null, pixelSnapping:String="auto", smoothing:Boolean=false)
		{
			
			super(this, bmpData, pixelSnapping, smoothing);
			
			// original bitmap
			_originalBitmap = bmpData.clone();
		}
		
		
		
		/**
		 * <p>setter bitmapData</p>
		 * 
		 * @param bmpData
		 * 
		 */		
		override public function set bitmapData(bmpData : BitmapData) : void 
		{
			
			_originalBitmap = bmpData.clone();
			if (_scale9Grid != null) 
			{
				if (!validGrid(_scale9Grid)) 
				{
					_scale9Grid = null;
				}
				resize(bmpData.width, bmpData.height);
			}
			else 
			{
				assignBitmapData(_originalBitmap.clone());
			}
			
		} 

		/**
		 * <p>setter width</p>
		 * 
		 * @param w
		 * 
		 */		 
		override public function set width(w : Number) : void 
		{
			if (w != width) 
			{
				resize(w, height);
			}
		}

		/**
		 * <p>setter height</p>
		 * 
		 * @param h
		 * 
		 */		 
		override public function set height(h : Number) : void 
		{
			if (h != height) 
			{
				resize(width, h);
			}
		}

		/**
		 * <p>set scale9Grid</p>
		 * 
		 * @param r
		 * 
		 */		 
		override public function set scale9Grid(r : Rectangle) : void 
		{
			// Check if the given grid is different from the current one
			if ((_scale9Grid == null && r != null) || (_scale9Grid != null && !_scale9Grid.equals(r))) 
			{
				if (r == null) 
				{
					// If deleting scalee9Grid, restore the original bitmap
					// then resize it (streched) to the previously set dimensions
					var currentWidth : Number = width;
					var currentHeight : Number = height;
					_scale9Grid = null;
					assignBitmapData(_originalBitmap.clone());
					resize(currentWidth, currentHeight);
				}
				else
				{
					if (!validGrid(r))
					{
						throw (new Error("#001 - The _scale9Grid does not match the original BitmapData"));
						return;
					}
					
					_scale9Grid = r.clone();
					resizeBitmap(width, height);
					scaleX = 1;
					scaleY = 1;
				}
			}
		}

		/**
		 * assignBitmapData
		 * Update the effective bitmapData
		 * 
		 * @param bmp
		 * 
		 */		
		private function assignBitmapData(bmp : BitmapData) : void 
		{
			super.bitmapData.dispose();
			super.bitmapData = bmp;
		}
		
		/**
		 * 
		 * @param r
		 * @return 
		 * 
		 */		
		private function validGrid(r : Rectangle) : Boolean 
		{
			return r.right <= _originalBitmap.width && r.bottom <= _originalBitmap.height;
		}

		/**
		 * <p>get scale9Grid</p>
		 */
		override public function get scale9Grid() : Rectangle 
		{
			return _scale9Grid;
		}

		
		/**
		 * <p>resize</p>
		 * 
		 * @param w
		 * @param h
		 * 
		 */		 
		public function resize(w : Number, h : Number) : void 
		{
			if (_scale9Grid == null) 
			{
				super.width = w;
				super.height = h;
			}
			else
			{
				w = Math.max(w, _originalBitmap.width - _scale9Grid.width);
				h = Math.max(h, _originalBitmap.height - _scale9Grid.height);
				resizeBitmap(w, h);
			}
		}

		/**
		 * <p>get original bitmap</p>
		 * 
		 * @return 
		 * 
		 */		 
		public function get originalBitmapData() : BitmapData 
		{
			return _originalBitmap;
		}

		/**
		 * <p>resize bitmap</p>
		 * 
		 * @param w
		 * @param h
		 * 
		 */		
		protected function resizeBitmap(w : Number, h : Number) : void 
		{
			
			var bmpData : BitmapData = new BitmapData(w, h, true, 0x00000000);
			
			var rows : Array = [0, _scale9Grid.top, _scale9Grid.bottom, _originalBitmap.height];
			var cols : Array = [0, _scale9Grid.left, _scale9Grid.right, _originalBitmap.width];
			
			var dRows : Array = [0, _scale9Grid.top, h - (_originalBitmap.height - _scale9Grid.bottom), h];
			var dCols : Array = [0, _scale9Grid.left, w - (_originalBitmap.width - _scale9Grid.right), w];

			var origin : Rectangle;
			var draw : Rectangle;
			var mat : Matrix = new Matrix();

			
			for (var cx : int = 0;cx < 3; cx++) 
			{
				for (var cy : int = 0 ;cy < 3; cy++) 
				{
					origin = new Rectangle(cols[cx], rows[cy], cols[cx + 1] - cols[cx], rows[cy + 1] - rows[cy]);
					draw = new Rectangle(dCols[cx], dRows[cy], dCols[cx + 1] - dCols[cx], dRows[cy + 1] - dRows[cy]);
					mat.identity();
					mat.a = draw.width / origin.width;
					mat.d = draw.height / origin.height;
					mat.tx = draw.x - origin.x * mat.a;
					mat.ty = draw.y - origin.y * mat.d;
					bmpData.draw(_originalBitmap, mat, null, null, draw, smoothing);
				}
			}
			assignBitmapData(bmpData);
		}
		
	}
}